﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using TouchSocket.Core;

namespace myBackupClient.Backup
{
    public class CompareFolders
    {
        public static void Compare(XElement sourceXElement,string destinationRoot, string destinationDir , out HashSet<DirectoryFileInfo> addedFiles, out HashSet<DirectoryFileInfo> deletedFiles, out HashSet<DirectoryFileInfo> modifiedFiles, out HashSet<DirectoryFileInfo> addedDirs, out HashSet<DirectoryFileInfo> deletedDirs)
        {
            var destinationPath= Path.Combine(destinationRoot, destinationDir);
            var sourceFiles = sourceXElement.Elements("File");
            var destinationFiles = new string[0];
            if(Directory.Exists(destinationPath))
                destinationFiles= Directory.GetFiles(destinationPath, "*");
            var sourceFilesDict = new Dictionary<string, DirectoryFileInfo>();
            var destinationFilesDict = new Dictionary<string, DirectoryFileInfo>();

            Func<string, string, string> GetRelativePath = (fullPath, basePath) =>
            {
                if (!basePath.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal))
                {
                    basePath += Path.DirectorySeparatorChar;
                }
                var relativePath = fullPath.Substring(basePath.Length);
                return relativePath;
            };

            foreach (var file in sourceFiles.AsParallel())
            {
                var name = file.Attribute("Name").Value;
                var relativePath =Path.Combine(sourceXElement.Attribute("Name").Value, name);
                sourceFilesDict[relativePath] = new DirectoryFileInfo
                {
                    Name = name,
                    Path = relativePath,
                    CreationTime = Convert.ToDateTime(file.Attribute("CreationTime").Value),
                    LastWriteTime = Convert.ToDateTime(file.Attribute("LastWriteTime").Value),
                    Size = Convert.ToInt64(file.Attribute("Size").Value),
                };
            }
         
            foreach (var file in destinationFiles.AsParallel())
            {
                var relativePath = GetRelativePath(file, destinationRoot);
                destinationFilesDict[relativePath] = new DirectoryFileInfo 
                { 
                    Name=Path.GetFileName(relativePath),
                    Path = relativePath,
                    CreationTime =File.GetCreationTime(file),
                    LastWriteTime =File.GetLastWriteTime(file) ,
                    Size = new FileInfo(file).Length
                };
            }
             
            addedFiles = new HashSet<DirectoryFileInfo>();
            deletedFiles = new HashSet<DirectoryFileInfo>();
            modifiedFiles = new HashSet<DirectoryFileInfo>();

         
            foreach (var file in  sourceFilesDict.Keys)
            {
                if (!destinationFilesDict.ContainsKey(file))
                {
                    addedFiles.Add(sourceFilesDict[file]);
                }
            }
          
            foreach (var file in  destinationFilesDict.Keys)
            {
                if (!sourceFilesDict.ContainsKey(file))
                {
                    deletedFiles.Add(destinationFilesDict[file]);
                }
            }
            
            foreach (var file in destinationFilesDict.Keys)
            {
                if (sourceFilesDict.ContainsKey(file) && (sourceFilesDict[file].LastWriteTime != destinationFilesDict[file].LastWriteTime || sourceFilesDict[file].Size!= destinationFilesDict[file].Size))
                {
                    modifiedFiles.Add(sourceFilesDict[file]);
                }
            }
            var sourceFolders = sourceXElement.Elements("Directory");
            var destinationFolders = new string[0];
            if(Directory.Exists(destinationPath))
                destinationFolders= Directory.GetDirectories(destinationPath, "*");
            var sourceFoldersDict = new Dictionary<string, DirectoryFileInfo>();
            var destinationFoldersDict = new Dictionary<string, DirectoryFileInfo>();
            foreach (var dir in sourceFolders.AsParallel())
            {
                var relativePath = Path.Combine(sourceXElement.Attribute("Name").Value, dir.Attribute("Name").Value);
                sourceFoldersDict[relativePath] =new DirectoryFileInfo { Name= dir.Attribute("Name").Value, Path = relativePath };
            }
            foreach (var dir in destinationFolders.AsParallel())
            {
                var relativePath = GetRelativePath(dir, destinationRoot);
                destinationFoldersDict[relativePath] = new DirectoryFileInfo { Name =Path.GetFileName(relativePath), Path = relativePath };
            }
            
            addedDirs = new HashSet<DirectoryFileInfo>();
            deletedDirs = new HashSet<DirectoryFileInfo>();

             
            foreach (var file in  sourceFoldersDict.Keys)
            {
                if (!destinationFoldersDict.ContainsKey(file))
                {
                    addedDirs.Add(sourceFoldersDict[file]);
                }
            }
           
            foreach (var file in  destinationFoldersDict.Keys)
            {
                if (!sourceFoldersDict.ContainsKey(file))
                {
                    deletedDirs.Add(destinationFoldersDict[file]);
                }
            }
        }
    }
}
